using System;
using System.Collections.Generic;
using System.Linq;
using Azure.Domain.Messages;
using Azure.Domain.Models;
using Azure.Infrastructure;

namespace Azure.Domain.Services
{
    public class BlogService : IBlogService
    {
        private readonly IRepository<Post> _blogRepository;
        private readonly ICache<Post> _blogCache;

        public BlogService(IRepository<Post> blogRepository, ICache<Post> blogCache)
        {
            _blogRepository = blogRepository;
            _blogCache = blogCache;
        }

        public virtual Post Create(NewPostMessage message)
        {
            var post = new Post
                           {
                               PartitionKey = Key.Partition(message.Created),
                               RowKey = Key.Row(message.Created),
                               Title = message.Title,
                               Body = message.Body,
                               Author = message.Author,
                               Created = message.Created,
                               Slug = message.Slug
                           };
            _blogRepository.Insert(post);
            _blogCache.Latest = post;

            return post;
        }

        public Post LatestPost()
        {
            Post result = _blogCache.Latest ?? _blogRepository.Last();

            return result;
        }

        public Post LoadPost(string partionKey, string rowKey)
        {
            var result = _blogCache.Get(partionKey, rowKey);
            if (result == null)
            {
                result = _blogRepository.Load(partionKey, rowKey);
                if (result != null)
                {
                    _blogCache.Add(result);
                }
            }

            return result;
        }

        public Post LoadPost(int year, int month, int day, string slug)
        {
            var query = from p in _blogRepository.Table
                        where p.PartitionKey == Key.Partition(year, month, day) && p.Slug == slug
                        select p;

            var posts = _blogRepository.Query(query.Take(1));

            return posts.First();
        }

        public IEnumerable<Post> Last(int count)
        {
            return _blogRepository.Last(count);
        }

        public void UpdatePost(UpdatePostMessage updatePostMessage)
        {
            var post = LoadPost(updatePostMessage.PartitionKey, updatePostMessage.RowKey);
            if (post == null)
            {
                throw new InvalidOperationException("Specified post does not exit and cannot be updated.");
            }

            _blogRepository.Attach(post);
            post.Title = updatePostMessage.Title;
            post.Body = updatePostMessage.Body;
            post.Slug = updatePostMessage.Slug;

            _blogRepository.Update(post);
            _blogCache.Add(post);
        }
    }
}